Unix/Linux编程:创建、打开、读取等目录

您所在的位置:网站首页 linux创建父目录命令mkdir -m Unix/Linux编程:创建、打开、读取等目录

Unix/Linux编程:创建、打开、读取等目录

2024-07-17 13:54| 来源: 网络整理| 查看: 265

操作对象必须是目录,负责会报错:

在这里插入图片描述

创建目录:mkdir()

mkdir创建一个新的目录节点并把它链接至文件系统树。即

mkdir创建了这个目录的i-节点;分配了一个磁盘块用以存储它的内容;在目录中设置两个入口.和..,并正确配置了它们的i-节点号在它的父目录中增加了一个该节点的链接

mkdir()系统调用创建一个新目录:

SYNOPSIS #include #include int mkdir(const char *pathname, mode_t mode); pathname 参数指定了新目录的路径名。该路径名可以是相对路径,也可以是绝对路径。若具有该路径名的文件已经存在,则调用失败并将 errno 置为 EEXISTmode 参数指定了新目录的权限。注意,set-user-ID 位始终处于关闭状态,因为该位对于目录而言毫无意义。 如果在 mode 中设置了粘滞位(S_ISVTX),那么将对新目录设置该权限。调用将忽略在 mode 中设置的 set-group-ID 位(S_ISGID)----只有父目录是set-group-ID 位,则同样会对新建目录设置该权限

SUSv3 明文规定,mkdir()对 set-user-ID、set-group-ID 以及粘滞位的处理方式由实现定义。某些 UNIX 实现在新建目录时总是关闭这 3 个权限位。

新建目录包括两个条目:.(点),即指向目录自身的链接;…(点点),即指向父目录的链接

mkdir()系统调用所创建的仅仅是路径名中的最后一部分。换言之,mkdir(“aaa/bbb/ccc”,mode)仅当目录 aaa 和 aaa/bbb 已经存在的情况下才会成功。

GNU C 语言库提供有 mkdtemp(template)函数,可谓 mkstemp()函数的“目录”版。该函数会创建一个唯一命名的目录,在对所有者开启读、写和执行权限的同时,不对任何其他用户赋予任何权限。不过,mkdtemp()所返回的并非一个文件描述符,而是一枚指针,指向经过修改处理的字符串,内含 template 中的实际目录名。该函数并未纳入 SUSv3 规范,也未获得所有 UNIX 实现的支持,但 SUSv4 对其作了定义

删除空目录:rmdir()

rmdir:从目录树种删除一个目录节点

这个目录必须是空的。即除了.和..的入口,这个目录不能包含其他任何的文件和子目录同时在父目录中删除这个目录的链接。如果这个目录本身并未被其他进程占用,它的i-节点和数据块将被释放

rmdir()系统调用移除由pathname指定的目录,该目录可以是绝对路径名,也可以是相对路径名。

NAME rmdir - delete a directory SYNOPSIS #include int rmdir(const char *pathname); DESCRIPTION rmdir() deletes a directory, which must be empty. RETURN VALUE On success, zero is returned. On error, -1 is returned, and errno is set appro‐ priately.

要使rmdir()调用成功,则要删除的目录必须为空。如果pathname的最后一部分为符号链接,那么rmdir调用将不对其进行解引用操作,并返回错误,同时将errno置为ENOTDIR

移除一个文件或者空目录:remove()

remove()库函数移除一个文件或者一个空目录

NAME remove - remove a file or directory SYNOPSIS #include int remove(const char *pathname); 如果pathname是一个文件,那么remove()将去调用unlink()如果pathname是一个目录,那么remove()将去调用rmdir()

与unlink()、rmdir()一样,remove()不对符号链接进行解引用操作。如果pathname是一符号链接,那么remove()会移除链接本身,而不是链接所指的文件。

如果移除一个文件只是为创建同名新文件做准备,那么编码时使用的remove()函数将会更加简单,无需再去检测路径是文件还是目录,然后再决定去调用unlink()或者rmdir()

读目录:opendir()、readdir() NAME opendir, fdopendir - open a directory SYNOPSIS #include #include DIR *opendir(const char *name); DIR *fdopendir(int fd);

opendir()函数打开一个目录,并返回指向该目录的句柄,供后继调用使用:

opendir()函数打开由name指定的目录,并返回指向DIR类型结构的指针。该结构就是所谓的目录流(directory stream),也是调用者传递给其他函数的句柄一旦从opendir()返回,则将目录流指向目录列表的首条记录。

除了要创建的目录流所针对的目录由打开文件描述符指代之外,fdopendir()与 opendir()并无不同。

之所以引入fdopendir(),是为了令应用程序免受各种竞态条件的困扰。调用fdopendir()之后,文件描述符将处于系统的控制之下,而且除了利用下面的函数之外,程序不应采取其他任何方式对其进行访问。 SYNOPSIS #include struct dirent *readdir(DIR *dirp);

readdir()从一个目录流中读取连续的条目

每调用readdir()一次,就会从dirp所指代的目录流中读取下一目录条目,并返回一个指针,执行由静态分配而得的dirent结构: struct dirent { ino_t d_ino; /* Inode number */ char d_name[256]; /* Null-terminated filename */ }; 每次调用 readdir()都会覆盖该结构。

出于对程序可移植性的考虑,上述定义略去了 Linux dirent 结构中的各种非标准字段。这其中最令人感兴趣的当属 d_type,它同时获得了 BSD 流派的支持,但并未在其他 UNIX 系统中实现。该属性值用于标识命名于 d_name 之中文件的类型,诸如 DT_REG(普通文件)、DT_DIR(目录)、DT_LNK(符号链接)或 DT_FIFO(FIFO)。利用该属性值可省去为确定文件类型而对 lstat ()的调用

调用 lstat()(或者 stat(),如果应对符号链接解引用时)可获得 d_name 所指向文件的更多信息,其中,路径名由之前调opendir()时指定的 dirpath 参数与“/”字符以及 d_name 字段的返回值拼接组成

readdir()返回时并未对文件名进行排序,而是按照文件在目录中出现的天然次序(这取决于文件系统向目录添加文件时所遵循的次序,及其在删除文件后对目录列表中空隙的填补方式)。(命令 ls–f 对文件列表的排列与调用 readdir()时一样,均未做排序处理。)

一旦遇到目录结尾或是出错,readdir()将返回 NULL,针对后一种情况,还会设置 errno 以示具体错误。为了区别这两种情况,可编码如下

errno = 0; direntp = readdir(dirp); if(direntp == NULL){ if(errno != 0){ // handler error }else{ // reached end-of-directory } }

如果目录内容恰逢应用调用 readdir()扫描该目录时发生变化,那么应用程序可能无法观察到这些变动。SUSv3 明确指出,对readdir()是否会返回自上次调用 opendir()或 rewinddir()后在目录中增减的文件,规范不做要求。至于最后一次执行上述调用前就存在的文件,应确保其全部返回。

rewinddir()函数可将目录流回移到起点,以便对 readdir()的下一次调用将从目录的第一个文件开始

NAME rewinddir - reset directory stream SYNOPSIS #include #include void rewinddir(DIR *dirp);

closedir()函数将由 dirp 指代、处于打开状态的目录流关闭,同时释放流所使用的资源。

NAME closedir - close a directory SYNOPSIS #include #include int closedir(DIR *dirp);

SUSv3 还定义了两个高级函数:telldir()和 seekdir(),允许随机访问目录流。有关这些函数的深入信息请参考手册页。

readdir_r()函数 NAME readdir_r - read a directory SYNOPSIS #include int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);

readdir_r()函数是 readdir()的变体。二者之间语义上的关键差异在于前者是可重入的,而后者不是。这是因为 readdir_r()对文件条目的返回利用的是由调用者分配的 entry 参数,而 readdir()则是将信息置于静态分配的结构并返回其指针

目录流和文件描述符

有一个目录流,就有一个文件描述符与之关联。dirfd()函数返回与dirp目录流相关联的文件描述符:

#include #include int dirfd(DIR *dirp);

例如,将 dirfd()返回的文件描述符传递给 fchdir(),就可以把进程的当前工作目录改成相应目录。

这里值得一提的是,opendir()会为与目录流相关联的文件描述符自动设置 close-on-exec 标志(FD_CLOEXEC),以确保当执行 exec()时自动关闭该文件描述符。

实现一个ls // 扫描一个目录 #if defined(__APPLE__) /* Darwin requires this header before including */ #include #endif #include #include #include #include #include static void /* List all files in directory 'dirpath' */ listFiles(const char *dirpath) { DIR *dirp; struct dirent *dp; bool isCurrent; /* True if 'dirpath' is "." */ isCurrent = strcmp(dirpath, ".") == 0; dirp = opendir(dirpath); if (dirp == NULL) { printf("opendir failed on '%s'", dirpath); return; } for (;;) { errno = 0; /* To distinguish error from end-of-directory */ dp = readdir(dirp); if (dp == NULL) break; if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) continue; /* Skip . and .. */ if (!isCurrent) printf("%s/", dirpath); printf("%s\n", dp->d_name); } if (errno != 0){ perror("readdir"); exit(EXIT_FAILURE); } if (closedir(dirp) == -1){ perror("closedir"); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { if (argc > 1 && strcmp(argv[1], "--help") == 0){ printf("%s [dir-path...]\n", argv[0]); exit(EXIT_FAILURE); } if (argc == 1) listFiles("."); else for (argv++; *argv; argv++) listFiles(*argv); exit(EXIT_SUCCESS); }

在这里插入图片描述

总结

操作目录和操作文件是类似的

opendir打开一个目录readdir返回目录中的当前项closedir关闭目录seekdir、telldir、rewinddir与lseek功能连续 在这里插入图片描述 目录是文件的列表,更确切的说,每条记录对应一个文件或者子目录。通过readdir来读取目录中的记录,readdir返回一个指向目录的当前记录的指针,记录的类型是struct dirent中,dirent结构中的成员d_name用于存放文件名


【本文地址】


今日新闻


推荐新闻


    CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3